<template>
  <div class="ttt-input" :style="inputStyle">
    <slot name="left">
      <i v-if="leftIcon" class="iconfont pr20" :class="[leftIcon]"></i>
    </slot>
    <input v-bind="$attrs" :type="type" v-model="inputValue" @input="handleInput">
    <slot name="right">
      <div v-if="code" class="code">
        <div v-if="!codeVisible" @click="handleGetCode">{{ $t('index.verificationCode') }}</div>
        <i18n-t v-else tag="div" class="d-f gap5" keypath="index.codeRetry">
          <template #time>
            <t-countdown :time="60 * 1000" format="ss" @timeout="codeVisible = false" />
          </template>
        </i18n-t>
      </div>
      <i v-else-if="rightIcon" class="iconfont pl20" :class="[rightIcon]"></i>
    </slot>
  </div>
</template>

<script setup lang="ts">
import TCountdown from '../TCountdown/TCountdown.vue'
import { computed, ref, watch } from 'vue'
import type { CSSProperties, PropType } from 'vue'
import type { TInputBeforeSendParams } from '../types/components'

const emits = defineEmits<{
  (e: 'send'): void
  (e: 'input', ev: Event): void
  (e: 'update:modelValue', ev: string | number): void
}>()

const props = defineProps({
  // 绑定数据
  modelValue: {
    type: [String, Number] as PropType<string | number>,
    required: true
  },
  // 类型
  type: {
    type: String as PropType<HTMLInputElement['type']>,
    default: 'text'
  },
  // 文本最长字数
  length: {
    type: [Number, String] as PropType<string | number>,
    default: Infinity
  },
  // 最大值
  max: {
    type: [Number, String] as PropType<string | number>,
    default: Infinity
  },
  // 最大值
  min: {
    type: [Number, String] as PropType<string | number>,
    default: -Infinity
  },
  // 是否整数
  integer: {
    type: Boolean as PropType<boolean>,
    default: false
  },
  // 左边
  leftIcon: {
    type: String as PropType<string>,
    default: ''
  },
  // 右边
  rightIcon: {
    type: String as PropType<string>,
    default: ''
  },
  // 圆角
  radius: {
    type: [Boolean, String, Number] as PropType<boolean | string | number>,
    default: '8'
  },
  // 验证码
  code: {
    type: Boolean as PropType<boolean>,
    default: false
  },
  // 发送验证码前
  beforeSend: {
    type: Function as PropType<TInputBeforeSendParams>,
    default: null
  }
})

// 是否点击了验证码
const isClick = ref<boolean>(false)
// 验证码输入时验证码显示
const codeVisible = ref<boolean>(false)
// 输入框
const inputValue = ref<string | number>('')
// 输入样式
const inputStyle = computed<CSSProperties>((): CSSProperties => {
  let radius
  if (typeof props.radius === 'boolean') {
    radius = props.radius ? `9999999999999rem` : '0'
  } else {
    radius = `${props.radius}rem`
  }
  return {
    borderRadius: radius
  }
})

// 输入限制
const handleInput = (ev: Event) => {
  emits('input', ev)
  if (props.type === 'number') {
    const inputNum = Number(inputValue.value)
    const max = Number(props.max)
    const min = Number(props.min)
    if (props.integer && !Number.isInteger(inputNum)) {
      inputValue.value = Math.floor(inputNum)
    }
    if (inputNum >= max) inputValue.value = max
    if (inputNum <= min) inputValue.value = min || ''
  } else if (props.type === 'text') {
    const inputStr = String(inputValue.value)
    const len = Math.abs(Number(props.length))
    if (inputStr.length > len) inputValue.value = inputStr.slice(0, len)
  }
  emits('update:modelValue', inputValue.value)
}

// 获取验证码
const handleGetCode = () => {
  if (codeVisible.value) return
  if (props.beforeSend instanceof Function) {
    if (isClick.value) return
    isClick.value = true
    props.beforeSend((done: boolean) => {
      if (done) {
        codeVisible.value = true
        emits('send')
      }
      isClick.value = false
    })
    return
  }
  codeVisible.value = true
  emits('send')
}

watch(() => props.modelValue, (val: string | number) => {
  inputValue.value = val
})
</script>

<style scoped lang="scss">
.ttt-input {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  background-color: var(--input-bg);
  border-radius: 10rem;
  padding: 0 20rem;

  input {
    height: var(--input-height);
    outline: none;
    background-color: transparent;
  }
}
</style>
